/* OpenSceneGraph example, osganimate.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/
#include <osgViewer/Viewer>
#include <osgViewer/CompositeViewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgDB/ReadFile>

#include <osg/Geode>
#include <osg/Geometry>

#include <QtCore/QString>
#include <QtCore/QTimer>
#include <QtGui/QKeyEvent>
#include <QtGui/QApplication>
#include <QtOpenGL/QGLWidget>
using Qt::WindowFlags;

#include <iostream>

class AdapterWidget : public QGLWidget
{
	public:

		AdapterWidget( QWidget * parent = 0, const char * name = 0, const QGLWidget * shareWidget = 0, WindowFlags f = 0 );

		virtual ~AdapterWidget() {}

		osgViewer::GraphicsWindow* getGraphicsWindow() { return _gw.get(); }
		const osgViewer::GraphicsWindow* getGraphicsWindow() const { return _gw.get(); }

	protected:

		void init();

		virtual void resizeGL( int width, int height );
		virtual void keyPressEvent( QKeyEvent* event );
		virtual void keyReleaseEvent( QKeyEvent* event );
		virtual void mousePressEvent( QMouseEvent* event );
		virtual void mouseReleaseEvent( QMouseEvent* event );
		virtual void mouseMoveEvent( QMouseEvent* event );

		osg::ref_ptr<osgViewer::GraphicsWindowEmbedded> _gw;
};

AdapterWidget::AdapterWidget( QWidget * parent, const char * name, const QGLWidget * shareWidget, WindowFlags f):
	QGLWidget(parent, shareWidget, f)
{
	_gw = new osgViewer::GraphicsWindowEmbedded(0,0,width(),height());
}

void AdapterWidget::resizeGL( int width, int height )
{
	_gw->getEventQueue()->windowResize(0, 0, width, height );
	_gw->resized(0,0,width,height);
}

void AdapterWidget::keyPressEvent( QKeyEvent* event )
{
	_gw->getEventQueue()->keyPress( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data() ) );
}

void AdapterWidget::keyReleaseEvent( QKeyEvent* event )
{
	_gw->getEventQueue()->keyRelease( (osgGA::GUIEventAdapter::KeySymbol) *(event->text().toAscii().data() ) );
}

void AdapterWidget::mousePressEvent( QMouseEvent* event )
{
	int button = 0;
	switch(event->button())
	{
		case(Qt::LeftButton): button = 1; break;
		case(Qt::MidButton): button = 2; break;
		case(Qt::RightButton): button = 3; break;
		case(Qt::NoButton): button = 0; break;
		default: button = 0; break;
	}
	_gw->getEventQueue()->mouseButtonPress(event->x(), event->y(), button);
}

void AdapterWidget::mouseReleaseEvent( QMouseEvent* event )
{
	int button = 0;
	switch(event->button())
	{
		case(Qt::LeftButton): button = 1; break;
		case(Qt::MidButton): button = 2; break;
		case(Qt::RightButton): button = 3; break;
		case(Qt::NoButton): button = 0; break;
		default: button = 0; break;
	}
	_gw->getEventQueue()->mouseButtonRelease(event->x(), event->y(), button);
}

void AdapterWidget::mouseMoveEvent( QMouseEvent* event )
{
	_gw->getEventQueue()->mouseMotion(event->x(), event->y());
}

class ViewerQT : public osgViewer::Viewer, public AdapterWidget
{
	public: 

		ViewerQT(QWidget * parent = 0, const char * name = 0, const QGLWidget * shareWidget = 0, WindowFlags f = 0):
			AdapterWidget( parent, name, shareWidget, f )
		{
			getCamera()->setViewport(new osg::Viewport(0,0,width(),height()));
			getCamera()->setProjectionMatrixAsPerspective(30.0f, static_cast<double>(width())/static_cast<double>(height()), 1.0f, 10000.0f);
			getCamera()->setGraphicsContext(getGraphicsWindow());

			setThreadingModel(osgViewer::Viewer::SingleThreaded);

			connect(&_timer, SIGNAL(timeout()), this, SLOT(updateGL()));
			_timer.start(10);
		}

		virtual void paintGL()
		{
			frame();
		}

	protected:

		QTimer _timer;
};

osg::ref_ptr<osg::Node> createSceneGraph()
{
	// Create an object to store geometry in
	osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;

	// create an array of four vertices
	osg::ref_ptr<osg::Vec3Array> v = new osg::Vec3Array;
	geom->setVertexArray( v.get() );
	v->push_back( osg::Vec3( -1., 0., -1. ) );
	v->push_back( osg::Vec3(  1., 0., -1. ) );
	v->push_back( osg::Vec3(  1., 0.,  1. ) );
	v->push_back( osg::Vec3( -1., 0.,  1. ) );

	// create an array of four colors
	osg::ref_ptr<osg::Vec4Array> c = new osg::Vec4Array;
	geom->setColorArray( c.get() );
	geom->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
	c->push_back( osg::Vec4( 1., 0., 0., 1. ) );
	c->push_back( osg::Vec4( 0., 1., 0., 1. ) );
	c->push_back( osg::Vec4( 0., 0., 1., 1. ) );
	c->push_back( osg::Vec4( 1., 1., 1., 1. ) );

	// create an array for the single normal
	osg::ref_ptr<osg::Vec3Array> n = new osg::Vec3Array;
	geom->setNormalArray( n.get() );
	geom->setNormalBinding( osg::Geometry::BIND_OVERALL );
	n->push_back( osg::Vec3(0., -1., 0.) );

	// Draw a four vertex quad from the data
	geom->addPrimitiveSet(new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4) );

	// add the geometry (Drawable) to a geode and return the geode
	osg::ref_ptr<osg::Geode> geode = new osg::Geode;
	geode->addDrawable( geom.get() );
	return geode.get();
}

int main( int argc, char **argv )
{
	QApplication a( argc, argv );
//	if (argc<2) {
//		std::cout << argv[0] <<": requires filename argument." << std::endl;
//		return 1;
//	}

//	osg::ArgumentParser arguments(&argc, argv);

	// load the scene.
//	osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
//	if (!loadedModel) {
//		std::cout << argv[0] <<": No data loaded." << std::endl;
//		return 1;
//	}

	osg::ref_ptr<osg::Node> root = new osg::Node;
	root = createSceneGraph();
	
	
	ViewerQT* viewerWindow = new ViewerQT;
	viewerWindow->setCameraManipulator(new osgGA::TrackballManipulator);
//	viewerWindow->setSceneData(loadedModel.get());
	viewerWindow->setSceneData( root.get() );
	viewerWindow->show();
	a.connect( &a, SIGNAL(lastWindowClosed()), &a, SLOT(quit()) );
	return a.exec();
}

/*EOF*/
